package cn.aws360.boot.auth.api.service.impl;

import cn.aws360.boot.auth.api.LoginApi;
import cn.aws360.boot.auth.api.constant.enums.LoginTypeEnum;
import cn.aws360.boot.auth.api.exception.AuthExceptionEnum;
import cn.aws360.boot.auth.api.helper.LoginHelper;
import cn.aws360.boot.auth.api.pojo.properties.AuthProperties;
import cn.aws360.boot.auth.api.pojo.request.LoginUserQuery;
import cn.aws360.boot.auth.api.pojo.response.LoginUserModel;
import cn.aws360.boot.auth.api.service.AuthService;
import cn.aws360.boot.base.api.exception.ServiceException;
import cn.dev33.satoken.stp.StpInterface;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.ShearCaptcha;
import cn.hutool.captcha.generator.MathGenerator;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.math.Calculator;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static cn.aws360.boot.auth.api.constant.AuthConstant.*;

/**
 * @author junnan
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AuthServiceImpl implements AuthService, StpInterface {

    private final LoginApi loginApi;
    private final AuthProperties authProperties;
    private final StringRedisTemplate stringRedisTemplate;

    @Override
    public Map<String, Object> genCaptcha() {
        String uuid = UUID.fastUUID().toString(true);
        Map<String, Object> map = MapUtil.of("uuid", uuid);
        ShearCaptcha shearCaptcha = CaptchaUtil.createShearCaptcha(authProperties.getCaptchaWidth(), authProperties.getCaptchaHeight());
        shearCaptcha.setGenerator(new MathGenerator(1));
        map.put("captcha", shearCaptcha.getImageBase64Data());
        String captcha = (int) Calculator.conversion(shearCaptcha.getCode()) + "";
        stringRedisTemplate.opsForValue().set(CACHE_CAPTCHA_CODE + uuid, captcha, CACHE_CAPTCHA_EXPIRE, TimeUnit.MINUTES);
        return map;
    }

    @Override
    public LoginUserModel login(LoginUserQuery loginUserQuery) {
        LoginTypeEnum loginTypeEnum = LoginTypeEnum.getLoginEnum(loginUserQuery.getType());
        if (ObjectUtil.isNull(loginTypeEnum)) {
            throw new ServiceException(AuthExceptionEnum.AUTH_LOGIN_OPTION_ERROR);
        }

        switch (loginTypeEnum) {
            case PWD:
                return loginByPwd(loginUserQuery);
            case SMS:
                return loginBySms(loginUserQuery);
            case TPS:
                return loginByTps(loginUserQuery);
            default:
                break;
        }
        return null;
    }

    @Override
    public List<String> getRoleList(Object loginId, String loginType) {
        LoginUserModel loginUserModel = LoginHelper.getLoginUser();
        if (loginUserModel != null) {
            return loginUserModel.getRoleCodeList();
        }
        return null;
    }

    @Override
    public List<String> getPermissionList(Object loginId, String loginType) {
        LoginUserModel loginUserModel = LoginHelper.getLoginUser();
        if (loginUserModel != null) {
            return loginUserModel.getMenuPermList();
        }
        return null;
    }

    /**
     * 密码登录：1-非空校验，2-图片验证码校验，3-用户校验，4-封装用户实体
     *
     * @param loginUserQuery 登录请求参数
     * @return LoginUserModel
     */
    private LoginUserModel loginByPwd(LoginUserQuery loginUserQuery) {
        String username = loginUserQuery.getUsername();
        String password = loginUserQuery.getPassword();
        if (!StrUtil.isAllNotBlank(username, password)) {
            throw new ServiceException(AuthExceptionEnum.AUTH_PWD_USER_OR_PASS_BLANK);
        }

        loginApi.checkCaptcha(loginUserQuery.getUuid(), loginUserQuery.getCaptcha());

        LoginUserModel loginUserModel = loginApi.loadUserByName(username);
        if (ObjectUtil.isNull(loginUserModel) || !LoginHelper.matchesPassword(password, loginUserModel.getPassword())) {
            throw new ServiceException(AuthExceptionEnum.AUTH_PWD_USER_OR_PASS_ERROR);
        }

        return loginApi.wrapLoginUserPerm(loginUserModel);
    }

    /**
     * 短信登录：1-非空校验，2-短信验证码校验，3-手机校验，4-封装用户实体
     *
     * @param loginUserQuery 登录请求参数
     * @return LoginUserModel
     */
    private LoginUserModel loginBySms(LoginUserQuery loginUserQuery) {
        String mobile = loginUserQuery.getMobile();
        String captcha = loginUserQuery.getCaptcha();
        if (!StrUtil.isAllNotBlank(mobile, captcha)) {
            throw new ServiceException(AuthExceptionEnum.AUTH_SMS_MOBILE_CODE_BLANK);
        }

        String smsCode = stringRedisTemplate.opsForValue().get(CACHE_MOBILE_CODE + mobile);
        if (!captcha.equalsIgnoreCase(smsCode)) {
            throw new ServiceException(AuthExceptionEnum.AUTH_SMS_MOBILE_CODE_ERROR);
        }

        LoginUserModel loginUserModel = loginApi.loadUserByMobile(mobile);
        if (ObjectUtil.isNull(loginUserModel)) {
            throw new ServiceException(AuthExceptionEnum.AUTH_SMS_MOBILE_USER_ERROR);
        }

        return loginApi.wrapLoginUserPerm(loginUserModel);
    }

    /**
     * 三方登录：1-非空校验，2-UUID 校验，3-封装用户实体
     *
     * @param loginUserQuery 登录请求参数
     * @return LoginUserModel
     */
    private LoginUserModel loginByTps(LoginUserQuery loginUserQuery) {
        String uuid = loginUserQuery.getUuid();
        String username = loginUserQuery.getUsername();
        if (!StrUtil.isAllNotBlank(uuid, username)) {
            throw new ServiceException(AuthExceptionEnum.AUTH_TPS_UUID_OR_USER_BLANK);
        }

        LoginUserModel loginUserModel = loginApi.loadUserByTpsUuid(uuid);
        if (ObjectUtil.isNull(loginUserModel) || !username.equals(loginUserModel.getUsername())) {
            throw new ServiceException(AuthExceptionEnum.AUTH_TPS_UUID_OR_USER_ERROR);
        }

        return loginApi.wrapLoginUserPerm(loginUserModel);
    }

}
